#include <stdlib.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <math.h>

#include <GL/glut.h>

#include "ImageClass.h"
#include "imageload.h"

typedef unsigned char byte;

ImageClass *Imagem, *NovaImagem;

#define LIMIAR 220
// **********************************************************************
//  void ConvertBlackAndWhite()
//
//
// **********************************************************************
void ConvertBlackAndWhite()
{
// Tarefa 1:
//		Mude o valor do LIMIAR e veja os resultados

	int x,y;

	for(x=0;x<Imagem->SizeX();x++)
	{
		for(y=0;y<Imagem->SizeY();y++)
        {
             if (Imagem->GetPointIntensity(x,y) < LIMIAR)
			 {
				NovaImagem->DrawPixel(x, y,0,0,0);
			 }
			 else NovaImagem->DrawPixel(x, y,255,255,255);
		}
	}

};

// **********************************************************************
// void ConvertToGrayScale()
//   
//
// **********************************************************************
void GrayScale(double level)
{
// Tarefa 2:
//		Gerar uma imagem em tons de cinza 
//		Use os m�todos 
//			'ReadPixel' e 'DrawPixel' da classe 'ImageClass'
	
//Imagem->ReadPixel(GLint x, GLint y, unsigned char &r, unsigned char &g, unsigned char &b)
// Obt�m os valores R,G,B de um ponto X,Y da image

//Imagem->DrawPixel(GLint x, GLint y, unsigned char r, unsigned char g, unsigned char b)
	// Exibe na coordenada X,Y um ponto com a cor R,G,B na imagem 
	int x,y;
	byte r,g,b,nc;

	for(x=0;x<Imagem->SizeX();x++)
	{
		for(y=0;y<Imagem->SizeY();y++)
        {
			Imagem->ReadPixel(x,y,r,g,b);
			nc = level*((r+g+b)/3);
			NovaImagem->DrawPixel(x,y,nc,nc,nc);
		}
	}

}

void negativo()
{
	int x,y;
	byte r,g,b,nc;

	for(x=0;x<Imagem->SizeX();x++)
	{
		for(y=0;y<Imagem->SizeY();y++)
        {
			Imagem->ReadPixel(x,y,r,g,b);
			nc = 255-((r+g+b)/3);
			NovaImagem->DrawPixel(x,y,nc,nc,nc);
		}
	}	
}

void zoomout()
{
	int x,y;
	byte r,g,b;

	ImageClass *fotenha;
	fotenha = new ImageClass(NovaImagem->SizeX()/2,NovaImagem->SizeY()/2);
	for(x=0;x<NovaImagem->SizeX();x+=2)
	{
		for(y=0;y<NovaImagem->SizeY();y+=2)
        {
			
			NovaImagem->ReadPixel(x,y,r,g,b);
			
			fotenha->DrawPixel(x/2,y/2,r,g,b);
		}
	}		
	NovaImagem->Delete();
	NovaImagem = new ImageClass(fotenha->SizeX(),fotenha->SizeY());
	fotenha->CopyTo(NovaImagem);
	NovaImagem->SetPos(Imagem->SizeX()+5,0);	
}
void zoominQ() //Quadriculado
{
	int x,y;
	byte r,g,b;

	ImageClass *fotenha;
	fotenha = new ImageClass(NovaImagem->SizeX()*2,NovaImagem->SizeY()*2);
	for(x=0;x<NovaImagem->SizeX();x++)
	{
		for(y=0;y<NovaImagem->SizeY();y++)
        {
			
			NovaImagem->ReadPixel(x,y,r,g,b);
			
			fotenha->DrawPixel(x*2,y*2,r,g,b);
			fotenha->DrawPixel(x*2,y*2+1,r,g,b);
			fotenha->DrawPixel(x*2+1,y*2+1,r,g,b);
			fotenha->DrawPixel(x*2+1,y*2,r,g,b);
		}
	}		
	NovaImagem->Delete();
	NovaImagem = new ImageClass(fotenha->SizeX(),fotenha->SizeY());
	fotenha->CopyTo(NovaImagem);
	NovaImagem->SetPos(Imagem->SizeX()+5,0);
}
void zoominL() //Linear
{
	int x,y;
	byte r,g,b,r1,g1,b1,r2,g2,b2;

	ImageClass *fotenha;
	fotenha = new ImageClass(NovaImagem->SizeX()*2-1,NovaImagem->SizeY()*2-1);
	
	for(y=0;y<NovaImagem->SizeY();y++)
	{
		for(x=0;x<NovaImagem->SizeX()-1;x++)
        {
			
			NovaImagem->ReadPixel(x,y,r1,g1,b1);
			NovaImagem->ReadPixel(x+1,y,r2,g2,b2);
			r = (r1+r2)/2;
			g = (g1+g2)/2;
			b = (b1+b2)/2;
			
			fotenha->DrawPixel(x*2,y*2,r1,g1,b1);
			fotenha->DrawPixel(x*2+1,y*2,r,g,b);
		}
		fotenha->DrawPixel(x*2,y*2,r2,g2,b2);
	}
	
	for(x=0;x<fotenha->SizeX();x++)
	{
		for(y=0;y<fotenha->SizeY()-1;y+=2)
        {
			
			fotenha->ReadPixel(x,y,r1,g1,b1);
			fotenha->ReadPixel(x,y+2,r2,g2,b2);
			r = (r1+r2)/2;
			g = (g1+g2)/2;
			b = (b1+b2)/2;
			
			fotenha->DrawPixel(x,y+1,r,g,b);
		}
		fotenha->DrawPixel(x,y,r2,g2,b2);
	}	

	
	NovaImagem->Delete();
	NovaImagem = new ImageClass(fotenha->SizeX(),fotenha->SizeY());
	fotenha->CopyTo(NovaImagem);
	NovaImagem->SetPos(Imagem->SizeX()+5,0);	
}

void equalizahistograma()
{
	
}
void media()
{
	
}
void lapaciano()
{
	
}
void sobel()
{
	
}
void mediana()
{
	
}


// **********************************************************************
//  void init(void)
//		Inicializa os par�metros globais de OpenGL
//      Cria os objetos que representam as imagens
//
// **********************************************************************
void init(void)
{
	int r;

	glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // Fundo de tela preto

    // Cria um objeto imagem
	Imagem = new ImageClass();
	r = Imagem->Load("f5.bmp");  // Leitura da Imagem
	if (!r)
    {
        printf("Imagem nao encontrada. Verifique o nome do Arquivo.\n");
        printf("Pressione ENTRE para encerrar.");
        getchar();
		exit(1);
    }
	else printf ("Imagem carregada!\n");

	// Instacia o objeto que ir� exibir a nova imagem 
	// Caso precise alterar o tamanho da nova imagem, mude os par�metros
	// da construtura, na chamada abaixo
	NovaImagem = new ImageClass(Imagem->SizeX(), Imagem->SizeY());
	
	// Posiciona a imagem nova ao lado da antiga
	NovaImagem->SetPos(Imagem->SizeX()+10, 0);
	Imagem->CopyTo(NovaImagem);
//	NovaImagem->DrawLineV(10,2, 100, 0,0,0);
//	ConvertBlackAndWhite();
//    GrayScale();
	
}

// **********************************************************************
//  void reshape( int w, int h )
//		trata o redimensionamento da janela OpenGL
//
// **********************************************************************
void reshape( int w, int h )
{

	// Reset the coordinate system before modifying
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	// Set the viewport to be the entire window
    glViewport(0, 0, w, h);
	gluOrtho2D(0,w,0,h);

	// Set the clipping volume
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();


}
// **********************************************************************
//  void display( void )
//      Esta rotina � chamada toda vez que a tela precisa ser 
//  redesenhada e toda vez qua a rotina 'glutPostRedisplay' � chamada
//
// **********************************************************************
void display( void )
{

	glClear(GL_COLOR_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	Imagem->Display();
	NovaImagem->Display();

	glutSwapBuffers();
}


// **********************************************************************
//  void keyboard ( unsigned char key, int x, int y )
//
//
// **********************************************************************
void keyboard ( unsigned char key, int x, int y )  
{
	static double level=1;
	switch ( key ) 
	{
		case 27:        // Termina o programa qdo
			exit ( 0 );   // a tecla ESC for pressionada
			break; 
		case '1':
				NovaImagem->Clear();
				glutPostRedisplay();
				break;
		case '2': 
				ConvertBlackAndWhite();				
				glutPostRedisplay(); // obrigat�rio para redesenhar a tela
 				break;
		case '3':
				GrayScale(1.0);
				glutPostRedisplay();
				break;
		case '4':
				negativo();
				glutPostRedisplay();
				break;
		case '5':
				level -= 0.1;
				GrayScale(level);
				glutPostRedisplay();
				break;
		case '6':
				level += 0.1;
				GrayScale(level);
				glutPostRedisplay();
				break;
		case '=':
				zoominQ();
				glutPostRedisplay();
				break;
		case '-':
				zoomout();
				glutPostRedisplay();
				break;
		case '+':
				zoominL();
				glutPostRedisplay();
				break;
		default:        
			break;
	}
}

// **********************************************************************
//  void main ( int argc, char** argv )
// **********************************************************************
int main ( int argc, char** argv )   
{
	glutInit            ( &argc, argv ); 
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB );
	glutInitWindowPosition (0,0);

	// Define o tamanho da janela gr�fica do programa
	glutInitWindowSize  ( 650, 500); 
	glutCreateWindow    ( "Leitura de Imagens" );
		
	init ();
//	glutFullScreen();
	
	glutDisplayFunc ( display );  
	glutReshapeFunc ( reshape );
	glutKeyboardFunc ( keyboard );
	glutMainLoop ();     
    return 0;     
}



